package cn.dyp.com.logprint.serial;

import java.util.ArrayList;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;


import android.R.integer;
import android.annotation.SuppressLint;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;

import cn.dyp.com.logprint.ServerApp;
import cn.dyp.com.logprint.bean.Controller;
import cn.dyp.com.logprint.bean.Sensor;
import cn.dyp.com.logprint.serialport_api.ZigbeeAdapter;
import cn.dyp.com.logprint.ui.MainActivity;

// 串口读写service类, 作为service在后台运行
public class SerialportService extends Service {
	private static final String TAG = "SerialportService";

	private ServerApp mApp;
	public static boolean ifSIMULATE = false;// 是否模拟
	private static ArrayList<Sensor> gSensorList = new ArrayList<Sensor>(); // 传感器数组
	private static ArrayList<Controller> gControllerList = new ArrayList<Controller>(); // 控制器数组

	private MyHandler handler = null;
	private ZigbeeAdapter adapter;
	private Timer timer;// 定时器，每一秒钟取一次传感器数据
	// 广播接收器，用来接收来自Net server的命令
	private SendToSerialportServiceBroadcast mBroadcast;

	public static Date mStartTime;// 服务开始时间

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	@SuppressWarnings("deprecation")
	@Override
	public void onStart(Intent intent, int startId) {
		super.onStart(intent, startId);
		try {
			mApp = (ServerApp) getApplication();
			// 初始化传感器数组
			gSensorList.clear();
			gSensorList.add(new Sensor(Sensor.PM25_SENSOR, 0x00));
			gSensorList.add(new Sensor(Sensor.CO2_SENSOR, 0x00));
			gSensorList.add(new Sensor(Sensor.AIR_TMPER_SENSOR, 0x00));
			gSensorList.add(new Sensor(Sensor.AIR_HUMID_SENSOR, 0x01));
			gSensorList.add(new Sensor(Sensor.SOIL_TMPER_SENSOR, 0x00));
			gSensorList.add(new Sensor(Sensor.SOIL_HUMID_SENSOR, 0x01));
			gSensorList.add(new Sensor(Sensor.LIGHT_SENSOR, 0x00));

			// 初始化控制器数组
			gControllerList.clear();
			gControllerList.add(new Controller(Controller.WATER_PUMP_CONTORL,
					0x00));
			gControllerList
					.add(new Controller(Controller.BLOWER_CONTORL, 0x01));
			gControllerList
					.add(new Controller(Controller.BUZZER_CONTORL, 0x03));
			gControllerList.add(new Controller(Controller.ROADLAMP_CONTORL,
					0x02));

			handler = new MyHandler();
			// 创建 ZigbeeAdapter对象
			adapter = new ZigbeeAdapter(handler);
			// 调用接口，初始化外接Zigbee串口模块
			adapter.initSerial(MainActivity.devices[MainActivity.chose], 115200);
			// 调用外部接口，对外部Zigbee模块执行协议握手
			adapter.devHands();
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("gdevHands...,waiting for device address. ");
		// 启动定时器，周期性向外部设备请求传感数据。包括co2和pm2.5
		timer = new Timer();
		timer.schedule(new CO2SensorTask(), 1000, 1000);
		System.out.println("Serial Service Started. ");
	}

	@Override
	public void onCreate() {
		super.onCreate();
		// 在创建该服务时，要立刻注册相关广播接收器
		mBroadcast = new SendToSerialportServiceBroadcast();
		IntentFilter intentFilter = new IntentFilter();
		intentFilter
				.addAction("com.lenovo.agriculture.server.broadcat.senttoserialport");
		registerReceiver(mBroadcast, intentFilter);
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		// 释放定时器资源
		if (timer != null) {
			timer.cancel();
		}
		// 释放串口资源
		adapter.closeSerial();
		if (mBroadcast != null) {
			unregisterReceiver(mBroadcast);
		}
		Log.d(TAG, "Serial Service Stopped.");
	}

	// 处理来自外部设备上报的传感数据
	@SuppressLint("HandlerLeak")
	public final class MyHandler extends Handler {
		public void handleMessage(Message msg) {
			byte[] addr = null;
			switch (msg.what) {
			case 1:
				// 获取外接多个传感模块地址，用于后续对该模块进行数据请求
				String nameStr = msg.getData().getString("sensorName"); // 获取传感器名称
				addr = msg.getData().getByteArray("sensorAddr");// 获取传感器地址
				if (addr != null && nameStr != null) {
					mStartTime = new Date();// 记录服务器开始时间
					Log.d(TAG, "get sensor name : " + nameStr + ", addr :"
							+ addr);
					// 处理pm2.5, Co2和灯光传感器的地址
					if (nameStr.equals(Sensor.PM25_SENSOR)
							|| nameStr.equals(Sensor.CO2_SENSOR)
							|| nameStr.equals(Sensor.LIGHT_SENSOR)) {
						// 根据传感器名称设置传感器地址
						Sensor sensor = Sensor.getSensorByName(gSensorList,
								nameStr);
						if (sensor != null) {
							sensor.setAddr(addr);
						}
					}

					// 处理空气温湿度传感器的地址,它们共用一个地址
					if (nameStr.equals(Sensor.AIR_TMPER_SENSOR)) {
						Sensor sensor = Sensor.getSensorByName(gSensorList,
								nameStr);
						if (sensor != null) {
							sensor.setAddr(addr);
						}
						sensor = Sensor.getSensorByName(gSensorList,
								Sensor.AIR_HUMID_SENSOR);
						if (sensor != null) {
							sensor.setAddr(addr);
						}
					}

					// 处理土壤温湿度传感器的地址,它们共用一个地址
					if (nameStr.equals(Sensor.SOIL_TMPER_SENSOR)) {
						Sensor sensor = Sensor.getSensorByName(gSensorList,
								nameStr);
						if (sensor != null) {
							sensor.setAddr(addr);
						}
						sensor = Sensor.getSensorByName(gSensorList,
								Sensor.SOIL_HUMID_SENSOR);
						if (sensor != null) {
							sensor.setAddr(addr);
						}
					}

					// 处理控制器的地址
					if (nameStr.equals(Controller.WATER_PUMP_CONTORL)) {
						// 所有的控制器都共用一个地址
						for (Controller controller : gControllerList) {
							controller.setAddr(addr);
							// 获得控制器地址时，先关闭控制器
							adapter.controlAct(controller.getAddr(),
									controller.getSubDev(), 0x30);
							// controller.setStatus(0);
							threadWait();// 延时，预留时间给下位机处理
						}
					}
				}
				break;

			case 2:
				// 获取传感器上报数据
				addr = msg.getData().getByteArray("sensorAddr");// 获取传感器地址
				byte[] dataByte = msg.getData().getByteArray("sensorData");// 获取传感器数据
				int nSub = msg.getData().getInt("SubNum"); // 获取子设备地址
				if (addr != null && dataByte != null) {
					String addrStr = ZigbeeAdapter.Bytes2HexString(addr);
					try {
						float fi = Float.parseFloat(new String(dataByte));// 解析传感器数据
						int value = (int) fi;
						boolean isSuccess = false;
						// 获取传感器的值
						for (Sensor sensor : gSensorList) {
							// 先判断地址是否为空
							if (sensor.getAddr() == null) {
								continue;
							}
							// 遍历传感器列表，根据地址找到对应的传感器并设置对应的值
							if (addrStr.equals(ZigbeeAdapter
									.Bytes2HexString(sensor.getAddr()))
									&& sensor.getSubDev() == nSub) {
								sensor.setValue(value);
								isSuccess = true;
								// Log.d(TAG,
								// "recv "+sensor.getName()+"("+addr+") data : "+sensor.getValue());
							}
						}
						// 获取控制器的状态
						for (Controller controller : gControllerList) {
							// 先判断地址是否为空
							if (controller.getAddr() == null) {
								continue;
							}
							// 遍历控制器列表，根据地址找到对应的控制器并设置对应的值
							if (addrStr.equals(ZigbeeAdapter
									.Bytes2HexString(controller.getAddr()))
									&& controller.getSubDev() == nSub) {
								if ((dataByte[0] & 0xff) == 49) {
									controller.setStatus(1);
								} else if ((dataByte[0] & 0xff) == 48) {
									controller.setStatus(0);
								}
								isSuccess = true;
							}
						}
						if (!isSuccess) {
							// 发现未知设备的数据，通过日志打印出来
							Log.e(TAG, "recv unknown sensor, addr : " + addrStr);
						}
					} catch (NumberFormatException e) {
						e.printStackTrace();
					} catch (Exception e) {
						e.printStackTrace();
					}

					// 自动控制逻辑要在服务开启10秒以后再启动
					if (mStartTime != null && mApp.getControlAuto() > 0) {
						Date now = new Date();
						if (now.getTime() - mStartTime.getTime() > 10000) {
							Sensor pm25 = gSensorList.get(0);// PM2.5浓度传感器
							Sensor co2 = gSensorList.get(1);// CO2浓度传感器
							Sensor airT = gSensorList.get(2);// 空气温度传感器
							Sensor airH = gSensorList.get(3);// 空气湿度传感器
							Sensor soilT = gSensorList.get(4);// 土壤温度传感器
							Sensor soilH = gSensorList.get(5);// 土壤湿度传感器
							Sensor light = gSensorList.get(6);// 光照强度传感器

							Controller waterPump = gControllerList.get(0);// 水泵控制器
							Controller blower = gControllerList.get(1);// 风扇控制器
							Controller buzzer = gControllerList.get(2);// 蜂鸣器控制器
							Controller roadlamp = gControllerList.get(3);// 路灯控制器

							// 自动控制蜂鸣器
							int isOpenBuzzer = 0;// 0表示关闭，1表示打开
							// 任选一个传感器都可以跟报警器联动。只需要设置一个报警阀值，大于或者小于阀值都可以报警。
							if (pm25.getValue() > mApp.getMaxPm25()
									|| co2.getValue() > mApp.getMaxCo2()
									|| co2.getValue() < mApp.getMinCo2()
									|| airT.getValue() > mApp
											.getMaxAirTemperature()
									|| airT.getValue() < mApp
											.getMinAirTemperature()
									|| airH.getValue() > mApp
											.getMaxAirHumidity()
									|| airH.getValue() < mApp
											.getMinAirHumidity()
									|| soilT.getValue() > mApp
											.getMaxEarthTemperature()
									|| soilT.getValue() < mApp
											.getMinEarthTemperature()
									|| soilH.getValue() > mApp
											.getMaxEarthHumidity()
									|| soilH.getValue() < mApp
											.getMinEarthHumidity()
									|| light.getValue() > mApp.getMaxLight()
									|| light.getValue() < mApp.getMinLight()) {
								isOpenBuzzer = 1;
							}
							if (isOpenBuzzer > 0) {
								openControllerByName(buzzer.getName());
							} else {
								closeControllerByName(buzzer.getName());
							}

							// 自动控制水泵
							int isOpenWaterPump = 0;// 0表示关闭，1表示打开
							// 当土壤湿度低于阀值，打开水泵模拟灌溉。
							if (soilH.getValue() < mApp.getMinEarthHumidity()) {
								isOpenWaterPump = 1;
							}
							if (isOpenWaterPump > 0) {
								openControllerByName(waterPump.getName());
							} else {
								closeControllerByName(waterPump.getName());
							}

							// 自动控制风扇
							int isOpenBlower = 0;// 0表示关闭，1表示打开
							// 不管光照强度如何，如果CO2低于一个阀值就打开风扇换进新风。
							if (co2.getValue() < mApp.getMinCo2()) {
								isOpenBlower = 1;
							}
							if (isOpenBlower > 0) {
								openControllerByName(blower.getName());
							} else {
								closeControllerByName(blower.getName());
							}

							// 自动控制路灯
							int isOpenRoadlamp = 0;// 0表示关闭，1表示打开
							// 当光照不足时，开灯
							if (light.getValue() < mApp.getMinLight()) {
								isOpenRoadlamp = 1;
							}
							if (isOpenRoadlamp > 0) {
								openControllerByName(roadlamp.getName());
							} else {
								closeControllerByName(roadlamp.getName());
							}
						}
					}
				}
				break;
			default:
				break;
			}
		}
	};

	// 根据控制器名称打开相应的控制器
	public void openControllerByName(String name) {
		Controller controller = Controller.getControllerByName(gControllerList,
				name); // 找到控制器
		if (controller != null && controller.getAddr() != null) // 并且控制器的地址不能为空
		// && !controller.isStateON()) // 并且控制器当前不是打开状态
		{
			adapter.controlAct(controller.getAddr(), controller.getSubDev(),
					0x31);
			// controller.setStatus(1);
		}
	}

	// 根据控制器名称关闭相应的控制器
	public void closeControllerByName(String name) {
		Controller controller = Controller.getControllerByName(gControllerList,
				name); // 找到控制器
		if (controller != null && controller.getAddr() != null) // 并且控制器的地址不能为空
		// && !controller.isStateON()) // 并且控制器当前必须是打开状态
		{
			adapter.controlAct(controller.getAddr(), controller.getSubDev(),
					0x30);
			// controller.setStatus(0);
		}
	}

	// 线程等待
	public void threadWait() {
		try {
			Thread.sleep(500);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 定时发送消息给外部设备，请求传感数据，包括PM2.5和co2
	class CO2SensorTask extends TimerTask {
		@Override
		public void run() {
			if (ifSIMULATE) {
				for (Sensor sensor : gSensorList) {
					sensor.setValue((int) (System.currentTimeMillis() % 99));
				}
			} else {
				// 分别获取当前所有传感器的数据
				for (Sensor sensor : gSensorList) {
					if (sensor.getAddr() == null) {
						continue;
					}
					adapter.RequestDeviceData(sensor.getAddr(),
							(byte) sensor.getSubDev());
				}
			}
		}
	};

	// 通过传感器的名称获取传感器当前的值
	public static int getSensorValueByName(String name) {
		Sensor sensor = Sensor.getSensorByName(gSensorList, name);
		if (sensor != null) {
			return sensor.getValue();
		} else {
			return -1;
		}
	}

	// 通过控制器的名称获取控制器的开关状态
	public static int getControllerStatusByName(String name) {
		int status = 0;
		Controller controller = Controller.getControllerByName(gControllerList,
				name);
		if (controller != null) {
			status = controller.getStatus();
		}
		return status;
	}

	/*
	 * BroadcastReceiver也就是“广播接收者”的意思，顾名思义，它就是用来接收来自系统和应用中的广播。
	 * 在Android系统中，广播体现在方方面面，例如当开机完成后系统会产生一条广播，接收到这条广播就能实现开机启动服务的功能；
	 * 当网络状态改变时系统会产生一条广播，接收到这条广播就能及时地做出提示和保存数据等操作；当电池电量改变时，
	 * 系统会产生一条广播，接收到这条广播就能在电量低时告知用户及时保存进度，等等。
	 * Android中的广播机制设计的非常出色，很多事情原本需要开发者亲自操作的， 现在只需等待广播告知自己就可以了，大大减少了开发的工作量和开发周期。
	 */
	class SendToSerialportServiceBroadcast extends BroadcastReceiver {
		@Override
		public void onReceive(Context context, Intent intent) {
			// 用来接收http server或socket server的控制信息
			String message = intent.getStringExtra("message");
			String device = intent.getStringExtra("device");
			int isOpen = intent.getIntExtra("isOpen", -1); // 0 close control, 1
															// open control
			Log.d(TAG, "Broadcast recevie : " + message + "," + device + ","
					+ isOpen);

			if (message.equals("control")) {
				if (isOpen == 1) {
					openControllerByName(device);
				} else if (isOpen == 0) {
					closeControllerByName(device);
					// 每次给控制器发送命令以后要等待一点时间，便于下位机处理数据
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
}
